#pragma once
#include <metalc/block/mslab.h>
/* block，用于存放meta信息*/
/* 内存不够一次性向上层请求 */
/* 主要是为了减少dTLB的开销，同时也是为了节省内存以及方便对齐 */
typedef struct mblock{
	struct{
		/* 第一个cache行 */
		/* 当前 */
		struct{
			dlist_t node;
			hword_t mslab_nr;
		} CACHE_ALIGNED;
		
		struct{
			sword_t cnt;
		} CACHE_ALIGNED;
		/* 第二个cache行 */
	} ALIGN(sizeof(mslab_calign_t));
	mslab_calign_t msmt[];
} mblock_t;

/* 第一个slab是不完全的(可以不分配，因为4kb页下允许空洞) */

/* 用meta信息填满 */
/* mblock size*/
typedef struct mblock_conf {
	const size_t mblock_size;	/* 32MB */
	const size_t mblock_unit_size;	/* 64KB */
	const size_t mblock_nr;
} mblock_conf_t;
/* mblock是mslab_calign的数组 */
SAI size_t mblock_header_size(const size_t mslab_nr){
	return mslab_nr * sizeof(mslab_calign_t);
}
/* 从指针获得mblock */
SAI mblock_t *mblock_by_ptr(void *ptr, const size_t mblock_size){
	ASSERT(is_powerof2(mblock_size));
	return (mblock_t *)((paddr_t)ptr & (~(mblock_size - 1UL)));
}
/* 从指针获得mblock的 */
SAI mslab_t *mslab_by_ptr_from_mblock(void *ptr, const size_t mblock_size, const size_t mblock_unitsz){
	ASSERT(is_powerof2(mblock_unitsz) && is_powerof2(mblock_size));
	// if (!is_ptr_aligned(ptr, mblock_unitsz)){ dbg_printf("%p, alignment %lx\n", ptr, mblock_unitsz); }
	// ASSERT(is_ptr_aligned(ptr, mblock_unitsz));
	mblock_t *block = mblock_by_ptr(ptr, mblock_size);
	/* 计算idx */
	size_t idx = ((paddr_t)ptr - (paddr_t)block) / mblock_unitsz;
	ASSERT(idx >= 1);
	return (mslab_t *)(&block->msmt[idx - 1]);
}
SAI void *mblock_alloc(mblock_t *blk, size_t sz, const size_t mblock_size, const size_t mslab_size, const size_t mslab_nr){
	PARAM_USED(mblock_size);
	ASSERT(is_powerof2(mslab_size) && is_aligned(sz, mslab_size));
	ASSERT(is_ptr_aligned(blk, mblock_size));
	size_t req_nr = sz / mslab_size;

	if (blk->mslab_nr + req_nr > mslab_nr) return NULL_PTR;
	size_t idx = blk->mslab_nr;
	blk->mslab_nr += req_nr;
	ASSERT(idx >= 1 && idx < mslab_nr);
	// paddr_t ret_addr = ((paddr_t)blk + idx * mslab_size);
	// ASSERT((ret_addr >= ((paddr_t)blk + mblock_header_size(mslab_nr))) && (ret_addr < (paddr_t)blk + mblock_size));
	return (void *)((paddr_t)blk + idx * mslab_size); 
}
SAI bool_t mblock_is_empty(mblock_t *blk, const size_t mslab_nr){
	return (blk->mslab_nr == mslab_nr);
}
SAI void mblock_discard(mblock_t *blk, const size_t mslab_nr){
	PARAM_USED(blk, mslab_nr);
	// ASSERT(blk->mslab_nr == mslab_nr);
	// sword_t tmp = (sword_t)0 - mslab_nr;
	// faa(&blk->cnt, tmp);
}
/* 初始化 */
SAI mblock_t *mblock_init(void *ptr, size_t size, size_t max_nr){
	// ASSERT(size >= conf->mblock_size);
	PARAM_USED(size, max_nr);
	
	mblock_t *ret = (mblock_t *)ptr;
	dlist_init(&ret->node);
	ret->mslab_nr = 1;
	
	// ret->cnt = (sword_t)max_nr;
	return ret;
}
/* 从mblock中创建mslab */
// SAI mslab_t *mblock_alloc_mslab(mblock_t *block, size_t sz, mblock_conf_t *conf){
	
// 	if (block->mslab_nr < conf->mblock_nr)
// 		return (mslab_t *)(&block->msmt[block->mslab_nr++]);
// 	return (mslab_t *)NULL_PTR;
// }
/* 获得mslab初始指针 */
SAI void *mslab_usable_in_mblock(mslab_t *msmt, const size_t mblock_size, const size_t mblock_unitsz){
	/* 索引 */
	ASSERT(!is_ptr_aligned(msmt, mblock_unitsz));
	ASSERT(is_powerof2(mblock_unitsz) && is_powerof2(mblock_size));
	mblock_t *block = mblock_by_ptr(msmt, mblock_size);
	ASSERT((paddr_t)msmt > (paddr_t)block);
	size_t idx = ((paddr_t)msmt - (paddr_t)block) / sizeof(mslab_calign_t);
	ASSERT(idx >= 1);
	return (void *)((paddr_t)block + idx * mblock_unitsz);
}

/* 返回是否能被复用 */
SAI mblock_t *mblock_reclaim_mslab(mslab_t *msmt, size_t size, const size_t mblock_size, const size_t mblock_unitsize){
	mblock_t *mblk = mblock_by_ptr(msmt, mblock_size);
	
	PARAM_USED(mblk, size, mblock_size, mblock_unitsize);
	
// #ifdef WFSPAN_MADVISE_FREE
// 	/* 计数器满才允许释放 */
// 	sword_t nr = size/mblock_unitsize;
// 	if (faa(&mblk->cnt, nr) + nr == (sword_t)(WFSPAN_MBLOCK/mblock_unitsize)){
// 		/* 只有头部4kmeta 页不允许释放 */
// 		madvise((void *)((paddr_t)mblk + PAGE_SIZE), WFSPAN_MBLOCK - PAGE_SIZE, WFSPAN_MADVISE_FREE);
// 		return mblk;
// 	}
// #endif
	return NULL_PTR;
}